package com.study.springcloudgateway.filters;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.study.api.Result;
import com.study.springcloudgateway.handler.SeckillConditionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * @description：秒杀订单过滤器
 * @author：李军荣
 * @date: 2021/2/7 15:35
 */
@Slf4j
@Order(0)
@PropertySource(value="classpath:seckillFilter.properties")
@Component
public class SeckillOrderFilter implements GlobalFilter {

    @Value("#{'${seckill.ignoreUrls}'.split(',')}")
    List<String> ignoreUrls;

    @Autowired
    private SeckillConditionHandler seckillConditionHandler;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if(null != ignoreUrls && !ignoreUrls.contains(request.getPath().toString())){
            return chain.filter(exchange);
        }


        return DataBufferUtils.join(exchange.getRequest().getBody())
            .flatMap(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                String bodyString = "";
                try {
                    bodyString = new String(bytes, "utf-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                Result result = seckillConditionHandler.conditonHanlder(bodyString);
                if(result.getCode() == 200){
                    DataBufferUtils.release(dataBuffer);
                    Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                        DataBuffer buffer = exchange.getResponse().bufferFactory()
                                .wrap(bytes);
                        return Mono.just(buffer);
                    });

                    ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                            exchange.getRequest()) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return cachedFlux;
                        }
                    };
                    return chain.filter(exchange.mutate().request(mutatedRequest)
                            .build());
                }
                return error(exchange,result.getMsg());
            });
    }


    public Mono<Void> error(ServerWebExchange exchange, String msg){
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE);
        Result result = new Result.Builder().customize(msg).bulider();
        ObjectMapper objectMapper = new ObjectMapper();
        String re = "";
        try {
            re = objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            log.info("GATEWAY AuthLoginFilter Exception"+e);
        }
        DataBuffer dataBuffer = response.bufferFactory().wrap(re.getBytes());
        return  response.writeWith(Flux.just(dataBuffer));
    }
}
